#include "StdAfx.h"
#include "DeviceAsyncEventArgs.h"
#include "Device.h"
#include "DeviceInfo.h"

using namespace System::Runtime::InteropServices;

Microsoft::Robotics::ManagedBulkUsb::DeviceAsyncEventArgs::~DeviceAsyncEventArgs()
{
	if(handle != nullptr)
	{
		handle->Close();
	}
}

Microsoft::Robotics::ManagedBulkUsb::DeviceAsyncEventArgs::DeviceAsyncEventArgs(
    Device^ transport, 
    array<Byte>^ buffer,
    DeviceInfo_t* deviceInfo) 
    : AsyncEventArgs(transport, buffer), device(transport),
      handle(nullptr),
      waitHandle(nullptr),
      overlapped(nullptr),
      pNativeOverlapped(NULL),
      pdi(deviceInfo)
{
    // Prepare the wait handle (for the async i/o) and get the threadpool to wait
    // on our behalf.
    handle = gcnew AutoResetEvent(false);
    overlapped = gcnew Overlapped(0, 0, handle->SafeWaitHandle->DangerousGetHandle(), nullptr);

    waitHandle = ThreadPool::RegisterWaitForSingleObject(
        handle,
        gcnew WaitOrTimerCallback(this, &DeviceAsyncEventArgs::OnCompleted),
        nullptr,
        -1,
        false);

    // Pack the overlapped structure and pin the buffer
    pNativeOverlapped = overlapped->Pack(nullptr, buffer);

    this->pdi->AddRef();
}

void Microsoft::Robotics::ManagedBulkUsb::DeviceAsyncEventArgs::OnCompleted(Object^ state, bool timedOut)
{
    try
    {
        // Find out what happened
        device->GetOverlappedResult(this);

        // Signal to the client
        OnCompleted();
    }
    finally
    {
        if (pdi != nullptr)
        {
            pdi->Release();
            pdi = nullptr;
        }

        if (pNativeOverlapped)
        {
            Overlapped::Unpack(pNativeOverlapped);
            Overlapped::Free(pNativeOverlapped);
            pNativeOverlapped = 0;
        }

        if (waitHandle != nullptr)
        {
            waitHandle->Unregister(handle);
            waitHandle = nullptr;
        }

        if (handle != nullptr)
        {
            if (!handle->SafeWaitHandle->IsClosed)
            {
                handle->Close();
            }
            handle = nullptr;
        }
    }
}
